package com.cloudfun.campusshare.common.security;

import cn.hutool.core.collection.CollectionUtil;
import com.cloudfun.campusshare.common.constant.*;
import com.cloudfun.campusshare.common.exception.AccessDenyException;
import com.cloudfun.campusshare.common.exception.AuthenticationException;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.entity.UserEntity;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.service.RoleService;
import com.cloudfun.campusshare.service.UserRelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by Huqin on 2019/12/23
 */
@Slf4j
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Autowired
    private UserRelService userRelService;

    @Autowired
    private RoleService roleService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        AuthRequired authRequired = handlerMethod.getMethodAnnotation(AuthRequired.class);
        // 方法上没有注解，去类上找
        if (null == authRequired) {
            authRequired = handlerMethod.getBeanType().getAnnotation(AuthRequired.class);
        }
        // 没有注解表示都可以调用
        if (null == authRequired) {
            return true;
        }
        if (TokenType.TOOLKIT.equals(authRequired.type())) {
            Authentication auth = AuthenticationHolder.getAppAuth();
            if (null == auth) {
                throw new AuthenticationException("应用token错误");
            }

        } else {
            Authentication auth = AuthenticationHolder.getUserAuth();
            if (null == auth) {
                throw new AuthenticationException("用户未登录");
            }

        }
        this.authorization(authRequired);
        return true;
    }

    /**
     * 鉴权
     *
     * @param authRequired
     */
    private void authorization(AuthRequired authRequired) {
        UserEntity userEntity = userEntityRepo.findById(AuthenticationHolder.getUserId()).orElseThrow(() -> new AuthenticationException("账号不存在"));
        // 判断token中的认证权限与注解中的权限是否一致
        boolean flag = false;
        for (AuthType auth : authRequired.auth()) {
            if (auth.getCode() == AuthType.NAKE.getCode()) {
                flag = true;
                break;
            }
            flag = Integer.valueOf(auth.getCode()).equals(userEntity.getAuthType());
            if (!flag) {
                UserEntity merchant = userRelService.getUserMerchant(userEntity.getId());
                if (null != merchant && merchant.getAuthStatus() == AuthStatus.AUTH_SUCCESS.getCode()) {
                    flag = true;
                }
            }
        }
        if (!flag) {
            String errMsg = "token角色未认证，无法调用该接口";
            log.info(errMsg);
            throw new AccessDenyException("用户未认证，无法调用该接口");
        }

        if (authRequired.type().equals(TokenType.NORMAL)) {
            // 只有普通token才进行角色的校验
            Set<String> requireRoles = Stream.of(authRequired.role()).map(RoleType::toString).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(requireRoles)) {
                return;
            }
            Set<String> roleTypes = AuthenticationHolder.getUserAuth().getRoleTypes();
            if (!StringUtils.isEmpty(userEntity.getMerchantId())) {
                // 子账号
                Set<String> merchantRoleTypes = roleService.getRoleTypes(userEntity.getMerchantId());
                if (CollectionUtil.isNotEmpty(roleTypes) && CollectionUtil.isNotEmpty(merchantRoleTypes)) {
                    roleTypes.addAll(merchantRoleTypes);
                }
            }
            requireRoles.retainAll(roleTypes);
            if (CollectionUtils.isEmpty(requireRoles)) {
                throw new BusinessException(Code.ERROR,"接口强制鉴权，非对应用户不能访问该接口");
            }
        }
    }
}

